﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace StyleMVVM.ViewModel
{
	public class CustomDataModelViewModelType : Type
	{
		private Type viewModelType;
		private Type modelType;
		private Dictionary<string, PropertyInfo> propertyInfos;

		public CustomDataModelViewModelType(Type baseType, Type dataModelType)
		{
			viewModelType = baseType;
			modelType = dataModelType;

			Initalize();
		}

		private void Initalize()
		{
			propertyInfos = new Dictionary<string, PropertyInfo>();

			foreach (PropertyInfo viewModelProperty in viewModelType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
			{
				propertyInfos[viewModelProperty.Name] = viewModelProperty;
			}

			foreach (PropertyInfo declaredProperty in modelType.GetTypeInfo().DeclaredProperties)
			{
				if (!propertyInfos.ContainsKey(declaredProperty.Name))
				{
					propertyInfos[declaredProperty.Name] =
						new CustomDataModelViewModelPropertyInfo(viewModelType,
						                                         declaredProperty.Name,
						                                         declaredProperty.PropertyType,
						                                         declaredProperty.CanWrite);
				}
			}
		}

		public override object[] GetCustomAttributes(bool inherit)
		{
			return viewModelType.GetCustomAttributes(inherit);
		}

		public override bool IsDefined(Type attributeType, bool inherit)
		{
			return viewModelType.IsDefined(attributeType, inherit);
		}

		public override ConstructorInfo[] GetConstructors(BindingFlags bindingAttr)
		{
			return viewModelType.GetConstructors(bindingAttr);
		}

		public override Type GetInterface(string name, bool ignoreCase)
		{
			return viewModelType.GetInterface(name, ignoreCase);
		}

		public override Type[] GetInterfaces()
		{
			return viewModelType.GetInterfaces();
		}

		public override EventInfo GetEvent(string name, BindingFlags bindingAttr)
		{
			return viewModelType.GetEvent(name, bindingAttr);
		}

		public override EventInfo[] GetEvents(BindingFlags bindingAttr)
		{
			return viewModelType.GetEvents(bindingAttr);
		}

		public override Type[] GetNestedTypes(BindingFlags bindingAttr)
		{
			return viewModelType.GetNestedTypes(bindingAttr);
		}

		public override Type GetNestedType(string name, BindingFlags bindingAttr)
		{
			return viewModelType.GetNestedType(name, bindingAttr);
		}

		public override Type GetElementType()
		{
			return viewModelType.GetElementType();
		}

		protected override bool HasElementTypeImpl()
		{
			return viewModelType.HasElementType;
		}

		protected override PropertyInfo GetPropertyImpl(string name,
		                                                BindingFlags bindingAttr,
		                                                Binder binder,
		                                                Type returnType,
		                                                Type[] types,
		                                                ParameterModifier[] modifiers)
		{
			PropertyInfo returnValue = null;

			propertyInfos.TryGetValue(name, out returnValue);

			return returnValue;
		}

		public override PropertyInfo[] GetProperties(BindingFlags bindingAttr)
		{
			return propertyInfos.Values.ToArray();
		}

		protected override MethodInfo GetMethodImpl(string name,
		                                            BindingFlags bindingAttr,
		                                            Binder binder,
		                                            CallingConventions callConvention,
		                                            Type[] types,
		                                            ParameterModifier[] modifiers)
		{
			return viewModelType.GetMethod(name, bindingAttr, binder, callConvention, types, modifiers);
		}

		public override MethodInfo[] GetMethods(BindingFlags bindingAttr)
		{
			return viewModelType.GetMethods(bindingAttr);
		}

		public override FieldInfo GetField(string name, BindingFlags bindingAttr)
		{
			return viewModelType.GetField(name, bindingAttr);
		}

		public override FieldInfo[] GetFields(BindingFlags bindingAttr)
		{
			return viewModelType.GetFields(bindingAttr);
		}

		public override MemberInfo[] GetMembers(BindingFlags bindingAttr)
		{
			return viewModelType.GetMembers(bindingAttr);
		}

		protected override TypeAttributes GetAttributeFlagsImpl()
		{
			throw new NotImplementedException();
		}

		protected override bool IsArrayImpl()
		{
			return viewModelType.IsArray;
		}

		protected override bool IsByRefImpl()
		{
			return viewModelType.IsByRef;
		}

		protected override bool IsPointerImpl()
		{
			return viewModelType.IsPointer;
		}

		protected override bool IsPrimitiveImpl()
		{
			return false;
		}

		protected override bool IsCOMObjectImpl()
		{
			return viewModelType.IsCOMObject;
		}

		public override object InvokeMember(string name,
		                                    BindingFlags invokeAttr,
		                                    Binder binder,
		                                    object target,
		                                    object[] args,
		                                    ParameterModifier[] modifiers,
		                                    CultureInfo culture,
		                                    string[] namedParameters)
		{
			return viewModelType.InvokeMember(name, invokeAttr, binder, target, args, modifiers, culture, namedParameters);
		}

		public override Type UnderlyingSystemType
		{
			get { return viewModelType.UnderlyingSystemType; }
		}

		protected override ConstructorInfo GetConstructorImpl(BindingFlags bindingAttr,
		                                                      Binder binder,
		                                                      CallingConventions callConvention,
		                                                      Type[] types,
		                                                      ParameterModifier[] modifiers)
		{
			return viewModelType.GetConstructor(bindingAttr, binder, callConvention, types, modifiers);
		}

		public override string Name
		{
			get { return viewModelType.Name; }
		}

		public override Guid GUID
		{
			get { return viewModelType.GUID; }
		}

		public override System.Reflection.Module Module
		{
			get { return viewModelType.Module; }
		}

		public override Assembly Assembly
		{
			get { return viewModelType.Assembly; }
		}

		public override string FullName
		{
			get { return viewModelType.FullName; }
		}

		public override string Namespace
		{
			get { return viewModelType.Namespace; }
		}

		public override string AssemblyQualifiedName
		{
			get { return viewModelType.AssemblyQualifiedName; }
		}

		public override Type BaseType
		{
			get { return viewModelType.BaseType; }
		}

		public override object[] GetCustomAttributes(Type attributeType, bool inherit)
		{
			return viewModelType.GetCustomAttributes(attributeType, inherit);
		}

		public override bool ContainsGenericParameters
		{
			get { return viewModelType.ContainsGenericParameters; }
		}

		public override System.Collections.Generic.IEnumerable<CustomAttributeData> CustomAttributes
		{
			get { return viewModelType.CustomAttributes; }
		}

		public override MethodBase DeclaringMethod
		{
			get { return viewModelType.DeclaringMethod; }
		}

		public override Type DeclaringType
		{
			get { return viewModelType.DeclaringType; }
		}

		public override bool Equals(Type o)
		{
			return viewModelType == o;
		}

		public override Type[] FindInterfaces(TypeFilter filter, object filterCriteria)
		{
			return viewModelType.FindInterfaces(filter, filterCriteria);
		}

		public override MemberInfo[] FindMembers(MemberTypes memberType,
		                                         BindingFlags bindingAttr,
		                                         MemberFilter filter,
		                                         object filterCriteria)
		{
			return viewModelType.FindMembers(memberType, bindingAttr, filter, filterCriteria);
		}

		public override GenericParameterAttributes GenericParameterAttributes
		{
			get { return viewModelType.GenericParameterAttributes; }
		}

		public override int GenericParameterPosition
		{
			get { return viewModelType.GenericParameterPosition; }
		}

		public override Type[] GenericTypeArguments
		{
			get { return viewModelType.GenericTypeArguments; }
		}

		public override int GetArrayRank()
		{
			return viewModelType.GetArrayRank();
		}

		public override System.Collections.Generic.IList<CustomAttributeData> GetCustomAttributesData()
		{
			return viewModelType.GetCustomAttributesData();
		}

		public override MemberInfo[] GetDefaultMembers()
		{
			return viewModelType.GetDefaultMembers();
		}

		public override string GetEnumName(object value)
		{
			return viewModelType.GetEnumName(value);
		}

		public override string[] GetEnumNames()
		{
			return viewModelType.GetEnumNames();
		}

		public override Type GetEnumUnderlyingType()
		{
			return viewModelType.GetEnumUnderlyingType();
		}

		public override Array GetEnumValues()
		{
			return viewModelType.GetEnumValues();
		}

		public override EventInfo[] GetEvents()
		{
			return viewModelType.GetEvents();
		}

		public override Type[] GetGenericArguments()
		{
			return viewModelType.GetGenericArguments();
		}

		public override Type[] GetGenericParameterConstraints()
		{
			return viewModelType.GetGenericParameterConstraints();
		}

		public override Type GetGenericTypeDefinition()
		{
			return viewModelType.GetGenericTypeDefinition();
		}

		public override InterfaceMapping GetInterfaceMap(Type interfaceType)
		{
			return viewModelType.GetInterfaceMap(interfaceType);
		}

		public override MemberInfo[] GetMember(string name, BindingFlags bindingAttr)
		{
			return viewModelType.GetMember(name, bindingAttr);
		}

		public override MemberInfo[] GetMember(string name, MemberTypes type, BindingFlags bindingAttr)
		{
			return viewModelType.GetMember(name, type, bindingAttr);
		}

		public override bool IsAssignableFrom(Type c)
		{
			return viewModelType.IsAssignableFrom(c);
		}

		public override bool IsConstructedGenericType
		{
			get { return viewModelType.IsConstructedGenericType; }
		}

		public override bool IsEnum
		{
			get { return viewModelType.IsEnum; }
		}

		public override bool IsEnumDefined(object value)
		{
			return viewModelType.IsEnumDefined(value);
		}

		public override bool IsEquivalentTo(Type other)
		{
			return viewModelType.IsEquivalentTo(other);
		}

		public override bool IsGenericParameter
		{
			get { return viewModelType.IsGenericParameter; }
		}

		public override bool IsGenericType
		{
			get { return viewModelType.IsGenericType; }
		}

		public override bool IsGenericTypeDefinition
		{
			get { return viewModelType.IsGenericTypeDefinition; }
		}

		public override bool IsInstanceOfType(object o)
		{
			return viewModelType.IsInstanceOfType(o);
		}

		public override bool IsSerializable
		{
			get { return viewModelType.IsSerializable; }
		}

		public override bool IsSubclassOf(Type c)
		{
			return viewModelType.IsSubclassOf(c);
		}

		public override RuntimeTypeHandle TypeHandle
		{
			get { return viewModelType.TypeHandle; }
		}

		public override Type MakeArrayType()
		{
			return viewModelType.MakeArrayType();
		}

		public override Type MakeArrayType(int rank)
		{
			return viewModelType.MakeArrayType(rank);
		}

		public override Type MakeByRefType()
		{
			return viewModelType.MakeByRefType();
		}

		public override Type MakeGenericType(params Type[] typeArguments)
		{
			return viewModelType.MakeGenericType(typeArguments);
		}

		public override Type MakePointerType()
		{
			return viewModelType.MakePointerType();
		}

		public override MemberTypes MemberType
		{
			get { return viewModelType.MemberType; }
		}

		public override int MetadataToken
		{
			get { return viewModelType.MetadataToken; }
		}

		public override Type ReflectedType
		{
			get { return viewModelType.ReflectedType; }
		}

		public override System.Runtime.InteropServices.StructLayoutAttribute StructLayoutAttribute
		{
			get { return viewModelType.StructLayoutAttribute; }
		}
	}
}